package com.mall.auth.controller;

import com.mall.auth.service.TokenService;
import com.mall.common.result.Result;
import com.mall.common.entity.User;
import com.mall.common.util.JwtUtil;
import com.mall.common.util.CaptchaUtil;
import com.mall.common.util.EmailUtil;
import com.mall.common.util.RedisUtil;
import com.mall.common.util.SmsUtil;
import com.mall.system.feign.MessageServiceFeignClient;
import com.mall.system.feign.UserServiceFeignClient;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 认证控制器
 */
@Tag(name = "认证接口")
@Slf4j
@RestController
@RequestMapping("/auth")
public class AuthController {
    
    @Autowired
    private UserServiceFeignClient userServiceFeignClient;
    
    @Autowired
    private TokenService tokenService;
    
    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private SmsUtil smsUtil;
    
    @Autowired
    private MessageServiceFeignClient messageServiceFeignClient;
    
    @Autowired
    private JavaMailSender mailSender;
    
    @Value("${jwt.secret:mall-secret}")
    private String jwtSecret;
    
    @Value("${jwt.expiration:3600000}")
    private Long jwtExpiration;
    
    /**
     * 用户登录 - 账号/手机号/邮箱 + 密码 + 图形验证码
     */
    @Operation(summary = "用户登录 - 账号/手机号/邮箱 + 密码 + 图形验证码")
    @PostMapping("/login")
    public Result<Object> login(@RequestParam String identifier, 
                                @RequestParam String password,
                                @RequestParam String captchaCode,
                                @RequestParam String captchaKey) {
        try {
            // 验证验证码
            if (!validateCaptcha(captchaKey, captchaCode)) {
                return Result.failed("验证码错误或已过期");
            }
            
            // 根据identifier获取用户（可能是用户名、手机号或邮箱）
            Result<User> result = getUserByIdentifier(identifier);
            if (!result.getCode().equals(200) || result.getData() == null) {
                return Result.failed("用户不存在");
            }
            
            User user = result.getData();
            
            // 验证密码
            String md5Password = org.springframework.util.DigestUtils.md5DigestAsHex(password.getBytes());
            if (!md5Password.equals(user.getPassword())) {
                return Result.failed("密码错误");
            }
            
            if (user.getStatus() == 0) {
                return Result.failed("账号已被禁用");
            }
            
            // 生成Token
            String token = generateToken(user);
            Map<String, Object> tokenResult = new HashMap<>(2);
            tokenResult.put("token", token);
            tokenResult.put("tokenType", "Bearer");
            return Result.success(tokenResult);
        } catch (Exception e) {
            log.error("用户登录异常: ", e);
            return Result.failed("登录失败: " + e.getMessage());
        }
    }
    
    /**
     * 用户登录 - 手机号/邮箱 + 短信验证码
     */
    @Operation(summary = "用户登录 - 手机号/邮箱 + 短信验证码")
    @PostMapping("/login/sms")
    public Result<Object> loginBySms(@RequestParam String identifier,
                                     @RequestParam String smsCode) {
        try {
            // 验证短信验证码
            if (!validateSmsCode(identifier, smsCode)) {
                return Result.failed("短信验证码错误或已过期");
            }
            
            // 根据identifier获取用户（手机号或邮箱）
            Result<User> result = getUserByIdentifier(identifier);
            if (!result.getCode().equals(200) || result.getData() == null) {
                return Result.failed("用户不存在");
            }
            
            User user = result.getData();
            
            if (user.getStatus() == 0) {
                return Result.failed("账号已被禁用");
            }
            
            // 生成Token
            String token = generateToken(user);
            Map<String, Object> tokenResult = new HashMap<>(2);
            tokenResult.put("token", token);
            tokenResult.put("tokenType", "Bearer");
            return Result.success(tokenResult);
        } catch (Exception e) {
            log.error("用户短信登录异常: ", e);
            return Result.failed("登录失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取验证码
     */
    @Operation(summary = "获取图形验证码")
    @GetMapping("/captcha")
    public Result<Object> getCaptcha() {
        try {
            // 生成验证码
            String code = CaptchaUtil.generateCaptchaCode();
            String key = "captcha:" + System.currentTimeMillis() + ":" + java.util.UUID.randomUUID().toString();
            
            // 存入Redis，有效期2分钟
            redisUtil.set(key, code, 120);
            
            // 生成验证码图片
            String imageBase64 = CaptchaUtil.generateCaptchaImage(code);
            
            Map<String, String> result = new HashMap<>(2);
            result.put("captchaKey", key);
            result.put("captchaImage", "data:image/png;base64," + imageBase64);
            
            return Result.success(result);
        } catch (Exception e) {
            log.error("生成验证码异常: ", e);
            return Result.failed("获取验证码失败: " + e.getMessage());
        }
    }
    
    /**
     * 发送短信验证码
     */
    @Operation(summary = "发送短信验证码")
    @PostMapping("/sms/code")
    public Result<Object> sendSmsCode(@RequestParam String mobile) {
        Long logId = null;
        try {
            // 生成短信验证码
            String code = String.format("%06d", new java.util.Random().nextInt(999999));
            
            // 存入Redis，有效期5分钟
            String key = "sms:code:" + mobile;
            redisUtil.set(key, code, 300);
            
            // 构造短信内容
            String content = "您的验证码是：" + code + "，5分钟内有效。";
            
            // 创建待发送短信记录
            Result<Long> pendingResult = messageServiceFeignClient.saveSmsLog(mobile, content, com.mall.common.constant.MessageStatusEnum.PENDING.getCode(), null);
            if (!pendingResult.getCode().equals(200) || pendingResult.getData() == null) {
                log.error("创建待发送短信记录失败: {}", mobile);
                return Result.failed("发送短信验证码失败");
            }
            logId = pendingResult.getData();
            
            // 调用短信服务发送验证码
            boolean sendResult = smsUtil.sendSms(mobile, code);
            
            // 根据发送结果更新短信日志状态
            if (sendResult) {
                messageServiceFeignClient.updateSmsLogStatus(logId, com.mall.common.constant.MessageStatusEnum.SUCCESS.getCode(), null);
            } else {
                messageServiceFeignClient.updateSmsLogStatus(logId, com.mall.common.constant.MessageStatusEnum.FAILED.getCode(), "短信发送失败");
                log.error("发送短信验证码失败: {}", mobile);
                return Result.failed("发送短信验证码失败");
            }
            
            log.info("短信验证码已生成: {} for mobile: {}", code, mobile);
            
            return Result.success("短信验证码已发送");
        } catch (Exception e) {
            // 发送异常时更新日志状态
            if (logId != null) {
                messageServiceFeignClient.updateSmsLogStatus(logId, com.mall.common.constant.MessageStatusEnum.FAILED.getCode(), "发送短信验证码异常: " + e.getMessage());
            }
            log.error("发送短信验证码异常: ", e);
            return Result.failed("发送短信验证码失败: " + e.getMessage());
        }
    }
    
    @Operation(summary = "用户登出")
    @PostMapping("/logout")
    public Result<Object> logout(@RequestHeader("Authorization") String authorization) {
        try {
            // 检查Authorization头
            if (authorization == null || !authorization.startsWith("Bearer ")) {
                return Result.failed("无效的Authorization头");
            }
            
            // 提取Token
            String token = authorization.substring(7);
            
            // 将Token加入黑名单
            boolean success = tokenService.addToBlacklist(token);
            if (success) {
                return Result.success("登出成功");
            } else {
                return Result.failed("登出失败");
            }
        } catch (Exception e) {
            log.error("用户登出异常: ", e);
            return Result.failed(e.getMessage());
        }
    }
    
    /**
     * 发送邮件验证码
     */
    @Operation(summary = "发送邮件验证码")
    @PostMapping("/email/code")
    public Result<Object> sendEmailCode(@RequestParam String email) {
        String content = ""; // 在try块外声明content变量
        String subject = "邮箱验证码"; // 在try块外声明subject变量
        Long logId = null;
        try {
            // 生成邮件验证码
            String code = String.format("%06d", new java.util.Random().nextInt(999999));
            
            // 存入Redis，有效期5分钟
            String key = "email:code:" + email;
            redisUtil.set(key, code, 300);
            
            // 构造邮件内容
            subject = "邮箱验证码";
            content = "您的验证码是：" + code + "，5分钟内有效。"; // 赋值给外部变量
            
            // 创建待发送邮件记录
            Result<Long> pendingResult = messageServiceFeignClient.saveEmailLog(email, subject, content, com.mall.common.constant.MessageStatusEnum.PENDING.getCode(), null);
            if (!pendingResult.getCode().equals(200) || pendingResult.getData() == null) {
                log.error("创建待发送邮件记录失败: {}", email);
                return Result.failed("发送邮件验证码失败");
            }
            logId = pendingResult.getData();
            
            // 调用邮件服务发送验证码
            boolean sendResult = EmailUtil.sendSimpleEmail(mailSender, "noreply@mall.com", email, subject, content);
            
            // 根据发送结果更新邮件日志状态
            if (sendResult) {
                messageServiceFeignClient.updateEmailLogStatus(logId, com.mall.common.constant.MessageStatusEnum.SUCCESS.getCode(), null);
            } else {
                messageServiceFeignClient.updateEmailLogStatus(logId, com.mall.common.constant.MessageStatusEnum.FAILED.getCode(), "邮件发送失败");
                log.error("发送邮件验证码失败: {}", email);
                return Result.failed("发送邮件验证码失败");
            }
            
            log.info("邮件验证码已生成: {} for email: {}", code, email);
            
            return Result.success("邮件验证码已发送");
        } catch (Exception e) {
            // 发送异常时更新日志状态
            if (logId != null) {
                messageServiceFeignClient.updateEmailLogStatus(logId, com.mall.common.constant.MessageStatusEnum.FAILED.getCode(), "发送邮件验证码异常: " + e.getMessage());
            }
            log.error("发送邮件验证码异常: ", e);
            return Result.failed("发送邮件验证码失败: " + e.getMessage());
        }
    }
    
    @Operation(summary = "用户注册")
    @PostMapping("/register")
    public Result<Object> register(@RequestBody User user) {
        try {
            // 通过Feign调用system服务注册用户
            Result<Boolean> result = userServiceFeignClient.register(user);
            if (result.getCode().equals(200) && result.getData()) {
                return Result.success("注册成功");
            } else {
                return Result.failed(result.getMessage() != null ? result.getMessage() : "注册失败");
            }
        } catch (Exception e) {
            log.error("用户注册异常: ", e);
            return Result.failed(e.getMessage());
        }
    }
    
    /**
     * 根据标识符（用户名/手机号/邮箱）获取用户
     */
    private Result<User> getUserByIdentifier(String identifier) {
        // 判断是手机号还是邮箱
        if (isValidMobile(identifier)) {
            return userServiceFeignClient.getUserByMobile(identifier);
        } else if (isValidEmail(identifier)) {
            return userServiceFeignClient.getUserByEmail(identifier);
        } else {
            // 默认按用户名查询
            return userServiceFeignClient.getUserByUsername(identifier);
        }
    }
    
    /**
     * 验证图形验证码
     */
    private boolean validateCaptcha(String captchaKey, String captchaCode) {
        if (!StringUtils.hasText(captchaKey) || !StringUtils.hasText(captchaCode)) {
            return false;
        }
        
        Object storedCode = redisUtil.get(captchaKey);
        if (storedCode == null) {
            return false;
        }
        
        // 验证后删除验证码
        redisUtil.del(captchaKey);
        
        return storedCode.toString().equalsIgnoreCase(captchaCode);
    }
    
    /**
     * 验证短信验证码
     */
    private boolean validateSmsCode(String identifier, String smsCode) {
        if (!StringUtils.hasText(identifier) || !StringUtils.hasText(smsCode)) {
            return false;
        }
        
        String key = "sms:code:" + identifier;
        Object storedCode = redisUtil.get(key);
        if (storedCode == null) {
            return false;
        }
        
        // 验证后删除验证码
        redisUtil.del(key);
        
        return storedCode.toString().equals(smsCode);
    }
    
    /**
     * 验证手机号
     */
    private boolean isValidMobile(String mobile) {
        return mobile != null && mobile.matches("^1[3-9]\\d{9}$");
    }
    
    /**
     * 验证邮箱
     */
    private boolean isValidEmail(String email) {
        return email != null && email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
    }
    
    /**
     * 生成JWT Token
     *
     * @param user 用户信息
     * @return Token
     */
    private String generateToken(User user) {
        Map<String, Object> claims = new HashMap<>(3);
        claims.put("userid", user.getUserId());
        claims.put("username", user.getUsername());
        claims.put("nickname", user.getNickname());
        
        // 使用JWT工具类生成Token
        return JwtUtil.generateToken(claims, jwtSecret, jwtExpiration);
    }
}